package ar.edu.itba.it.paw.web.product;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.wicket.Component;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.form.validation.AbstractFormValidator;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.PropertyListView;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.apache.wicket.validation.validator.MaximumValidator;
import org.apache.wicket.validation.validator.MinimumValidator;
import org.apache.wicket.validation.validator.StringValidator;


import ar.edu.itba.it.paw.domain.Auction;
import ar.edu.itba.it.paw.domain.EntityModel;
import ar.edu.itba.it.paw.domain.EntityResolver;
import ar.edu.itba.it.paw.domain.Offer;
import ar.edu.itba.it.paw.domain.Product;
import ar.edu.itba.it.paw.domain.Question;
import ar.edu.itba.it.paw.domain.Transaction;
import ar.edu.itba.it.paw.domain.User;
import ar.edu.itba.it.paw.domain.exceptions.InsufficientProductsException;
import ar.edu.itba.it.paw.domain.exceptions.InvalidOfferException;
import ar.edu.itba.it.paw.domain.exceptions.InvalidOperationException;
import ar.edu.itba.it.paw.repo.ProductRepo;
import ar.edu.itba.it.paw.repo.TransactionRepo;
import ar.edu.itba.it.paw.repo.UserRepo;
import ar.edu.itba.it.paw.web.MercadoLibre;
import ar.edu.itba.it.paw.web.MercadoLibreSession;
import ar.edu.itba.it.paw.web.base.BasePage;
import ar.edu.itba.it.paw.web.component.PriceLabel;
import ar.edu.itba.it.paw.web.component.ProductDetailPanel;
import ar.edu.itba.it.paw.web.component.TypeLabel;
import ar.edu.itba.it.paw.web.user.UserMenuPage;

public class ProductDetailPage extends BasePage{

	@SpringBean
	private ProductRepo prodRepo;
	@SpringBean
	private UserRepo userRepo;
	@SpringBean
	private TransactionRepo transactionRepo;

	private Integer buy_quantity;
	private String comment;
	private Float offer;
	private String question;

	public ProductDetailPage(Product product){
		
		product.visit();
		setDefaultModel(new CompoundPropertyModel<Product>(new EntityModel<Product>(Product.class,product)));
		
		/* Define product values */
		//		add(new Label("seller",new PropertyModel<String>(getDefaultModel(), "owner.username")).add(new SimpleAttributeModifier("style", "")));
		//		add(new Label("name").add(new SimpleAttributeModifier("style", "")));
		//		add(new Label("description").add(new SimpleAttributeModifier("style", "")));
		//		add(new Label("category",new PropertyModel<String>(getDefaultModel(), "category.name")).add(new SimpleAttributeModifier("style", "")));
		//		add(new Label("price").add(new SimpleAttributeModifier("style", "")));
		//		add(new Label("quantity").add(new SimpleAttributeModifier("style", "")));
		//		add(new Label("state", new ProductStateModel((IModel<Product>)getDefaultModel())).add(new SimpleAttributeModifier("style", "")));

		add(new ProductDetailPanel("ProdPanel",product));

		/* Feedback panel for buy form */
		Component buyFeedbackPanel = new FeedbackPanel("buy_feedback").add(new SimpleAttributeModifier("style", "color: #FF0000"));
		add(buyFeedbackPanel);	
		Form<ProductDetailPage> buyForm = new Form<ProductDetailPage>("buyForm", new CompoundPropertyModel<ProductDetailPage>(this)) {
			@Override
			protected void onSubmit() {
				MercadoLibreSession session = MercadoLibreSession.get();
				try{
					transactionRepo.buy(new Transaction(session.getUser(), ((Product)ProductDetailPage.this.getDefaultModelObject()).getOwner(), buy_quantity, new Date() , ((Product)ProductDetailPage.this.getDefaultModelObject())));
				}catch(InsufficientProductsException e){
					error(getString("invalid.quantity"));	
					return;
				}catch(InvalidOperationException e){
					error(getString("own.product.buy"));
					return;
				}
				//((Product)ProductDetailPage.this.getDefaultModelObject()).setQuantity(((Product)ProductDetailPage.this.getDefaultModelObject()).getQuantity() - buy_quantity);
				setResponsePage(UserMenuPage.class);
			}
		};

		buyForm.add(new TextField<Integer>("buy_quantity").setRequired(true).add(new MinimumValidator<Integer>(1)).add(new MaximumValidator<Integer>(((Product)getDefaultModelObject()).getQuantity())));
		buyForm.add(new TextField<String>("comment"));
		buyForm.add(new Button("buy", new ResourceModel("buy")));
		buyForm.add(new AbstractFormValidator() {
			
			@Override
			public void validate(Form<?> form) {
				if( MercadoLibreSession.get() == null ||  MercadoLibreSession.get().getUser() == null){
					form.error(getString("user.null"));
					return;
				}
			}
			
			@Override
			public FormComponent<?>[] getDependentFormComponents() {
				// TODO Auto-generated method stub
				return null;
			}
		});
	

		/* If it is an auction, i hide the buy form  */
		if(!(product.getClass() ==  Product.class) ){
			buyForm.setVisibilityAllowed(false);
			buyFeedbackPanel.setVisibilityAllowed(false);
		}
		add(buyForm);


		if(product instanceof Auction){
			add(new PriceLabel("maxOffer",new PropertyMaxOfferModel((IModel<Auction>)getDefaultModel())));
		}else{
			add(new Label("maxOffer"));
		}

		/* Feedback panel for offer form */
		Component offerFeedbackPanel = new FeedbackPanel("offer_feedback").add(new SimpleAttributeModifier("style", "color: #FF0000"));
		add(offerFeedbackPanel);
		Form<ProductDetailPage> offerForm = new Form<ProductDetailPage>("offerForm", new CompoundPropertyModel<ProductDetailPage>(this)) {
			@Override
			protected void onSubmit() {
				MercadoLibreSession session = MercadoLibreSession.get();
				
				try {
					((Auction)(ProductDetailPage.this.getDefaultModelObject())).addOffer(new Offer(offer,session.getUser(),new Date(),((Auction)(ProductDetailPage.this.getDefaultModelObject()))));
					setResponsePage(UserMenuPage.class);
				} catch (InvalidOfferException e) {
					error(getString("invalid.offer"));
					return;
				} catch (InvalidOperationException e) {
					error(getString("own.product.buy"));
					return;
				}
			}
		};
		if(product instanceof Auction){
			offerForm.add(new TextField<Float>("offer").setRequired(true).add(new MinimumValidator<Float>(((Auction)getDefaultModelObject()).getPrice())));	
		}else{
			offerForm.add(new TextField<Float>("offer").setRequired(true));
		}
		
		offerForm.add(new Button("offer_button", new ResourceModel("offer_button")));
		offerForm.add(new AbstractFormValidator() {
			
			@Override
			public void validate(Form<?> form) {
				MercadoLibreSession session = MercadoLibreSession.get();
				if(session == null || session.getUser() == null)
				{
					form.error(getString("user.null"));
					return;
				}
				if(((Auction)(ProductDetailPage.this.getDefaultModelObject())).isEnded()){
					form.error(getString("auction.ended"));
					return;
				}
				if(((Auction)(ProductDetailPage.this.getDefaultModelObject())).getOwner().equals(session.getUser())){
					form.error(getString("own.product.buy"));
					return;
				}
				
			}
			
			@Override
			public FormComponent<?>[] getDependentFormComponents() {
				return null;
			}
		});

		/* If it isnt an auction, hide the offer form and all possible offers*/
		IModel<List<Offer>> offerModel = new LoadableDetachableModel<List<Offer>>() {
			@Override
			protected List<Offer> load() {
				if(((Product)getDefaultModelObject()) instanceof Auction){
					return new ArrayList<Offer>(((Auction)getDefaultModelObject()).getOffers());
				}else{
					return new ArrayList<Offer>();
				}
			}
		};


		PropertyListView<Offer> offers = new PropertyListView<Offer>("offers", offerModel) {

			@Override
			protected void populateItem(ListItem<Offer> item) {
				item.add(new PriceLabel("price",new PropertyModel<Double>(item.getModel(), "offer")).add(new SimpleAttributeModifier("style", "color: #FFFFFF")));
				item.add(new Label("date", new PropertyModel<Offer>(item.getModel(), "offer_date")).add(new SimpleAttributeModifier("style", "")));
			}
		};

		add(offers);
		add(offerForm);
		if(!(product instanceof Auction) ){
			offerForm.setVisibilityAllowed(false);
			offers.setVisibilityAllowed(false);
			offerFeedbackPanel.setVisibilityAllowed(false);
		}


		IModel<List<Question>> questionModel = new LoadableDetachableModel<List<Question>>() {
			@Override
			protected List<Question> load() {
				return new ArrayList<Question>(((Product)getDefaultModelObject()).getQuestions());
			}
		};


		add(new PropertyListView<Question>("questions", questionModel) {

			@Override
			protected void populateItem(ListItem<Question> item) {
				item.add(new Label("question",new PropertyModel<Question>(item.getModel(), "question")).add(new SimpleAttributeModifier("style", "color: #FFFFFF")));
				item.add(new Label("date", new PropertyModel<Question>(item.getModel(), "date")).add(new SimpleAttributeModifier("style", "")));
				item.add(new Label("answer",new PropertyModel<Product>(item.getModel(), "answer") ).add(new SimpleAttributeModifier("style","color: #FFFFFF")));
			}
		});

		//add(new FeedbackPanel("new_question_feedback").add(new SimpleAttributeModifier("style", "color: #FF0000")));

		Form<ProductDetailPage> newQuestionForm = new Form<ProductDetailPage>("newQuestionForm", new CompoundPropertyModel<ProductDetailPage>(this)) {
			@Override
			protected void onSubmit() {
				MercadoLibreSession session = MercadoLibreSession.get();
				Product aux = ((Product)ProductDetailPage.this.getDefaultModelObject());
				aux.getQuestions().add(new Question(aux,session.getUser(),question,"",new Date()));
				setResponsePage(UserMenuPage.class);
			}
		};
		newQuestionForm.add(new TextField<String>("question").setRequired(true).add(StringValidator.maximumLength(255)));
		newQuestionForm.add(new Button("question_button", new ResourceModel("question_button")));
		newQuestionForm.add(new AbstractFormValidator() {
			
			@Override
			public void validate(Form<?> form) {
				MercadoLibreSession session = MercadoLibreSession.get();
				if(session == null || session.getUser() == null)
				{
					form.error(getString("user.null"));
					return;
				}
				if(((Product)ProductDetailPage.this.getDefaultModelObject()).getOwner().equals(session.getUser())){
					form.error(getString("question.myproduct"));
					return;
				}
				
			}
			
			@Override
			public FormComponent<?>[] getDependentFormComponents() {
				return null;
			}
		});
		add(newQuestionForm);


		IModel<List<Product>> productsModel = new LoadableDetachableModel<List<Product>>() {
			@Override
			protected List<Product> load() {
				List<Product> list = new ArrayList<Product>(((Product)getDefaultModelObject()).getOwner().getProducts_set()); 
				list.remove(((Product)getDefaultModelObject()));
				return list;
			}
		};


		add(new PropertyListView<Product>("sameUserProducts", productsModel) {

			@Override
			protected void populateItem(ListItem<Product> item) {
				item.add(new Label("name",new PropertyModel<Product>(item.getModel(), "name")).add(new SimpleAttributeModifier("style", "color: #0099FF")));
				item.add(new Label("description").add(new SimpleAttributeModifier("style", "")));
				item.add(new TypeLabel("type", item.getModel()));
				item.add(new Link<Product>("detail", item.getModel()) {
					@Override
					public void onClick() {
						setResponsePage(new ProductDetailPage(getModelObject()));
					}
				}.add(new Image("detail_image", MercadoLibre.DETAIL_ICON).add(new SimpleAttributeModifier("height","15px"))));
			}
		});
	}


	public class PropertyMaxOfferModel extends AbstractReadOnlyModel<Double>{

		IModel<Auction> auction;

		public PropertyMaxOfferModel(IModel<Auction> auction){
			this.auction = auction;
		}

		@Override
		public Double getObject() {
			return Double.valueOf(auction.getObject().getPrice());
		}

	}

}
